export function toMap (arr: any[], key1: string, key2: string) {
  const map = new Map()
  arr.forEach((item) => {
    map.set(item[key1] as string, item[key2] as string)
  })
  return map
}

export function toQueryString (obj: {
  [key: string]: string | number | boolean
}) {
  return Object.keys(obj)
    .map(function (key) {
      return encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])
    })
    .join('&')
}

export function secToTime (sec = 0): string {
  if (Number.isNaN(sec)) {
    return '00:00:00'
  }
  if (sec < 0) {
    return secToTime(sec + 86400)
  }
  const h = Math.floor(sec / 3600)
  const m = Math.floor((sec % 3600) / 60)
  const s = Math.floor(sec % 60)
  return `${fixZero(h)}:${fixZero(m)}:${fixZero(s)}`
}

export function fixZero (num: number): string {
  if (num < 10) {
    return '0' + num
  }
  return num + ''
}

export function secToTimecode (sec = 0, framerate = 30): string {
  if (sec < 0) {
    return secToTime(sec + 86400)
  }
  const h = Math.floor(sec / 3600)
  const m = Math.floor((sec % 3600) / 60)
  const s = Math.floor(sec % 60)
  const f = secToFrame(sec % 1, framerate)
  return `${fixZero(h)}:${fixZero(m)}:${fixZero(s)}:${fixZero(f)}`
}

export function frameToSec (frame = 0, framerate = 30): number {
  return frame / framerate
}

export function frameToTimecode (frame = 0, framerate = 30): string {
  const sec = frameToSec(frame, framerate)
  return secToTimecode(sec, framerate)
}

export function secToFrame (sec = 0, framerate = 30): number {
  if (sec < 0) {
    return secToFrame(sec + 86400, framerate)
  }
  let frame = 0
  if (framerate === 59.94) {
    frame = (sec * 60000) / 1001
  }
  if (framerate === 29.97) {
    frame = (sec * 30000) / 1001
  } else {
    frame = sec * framerate
  }
  return parseInt(frame.toFixed(0))
}

export function getCookie (name: string): string | null {
  let arr
  let reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
  if ((arr = document.cookie.match(reg))) return unescape(arr[2])
  else return null
}

export function setCookie (
  name: string,
  value: string,
  expires = 30 * 24 * 60 * 60 * 1000
) {
  let exp = new Date()
  exp.setTime(exp.getTime() + expires)
  document.cookie =
    name + '=' + escape(value) + ';path=/;expires=' + exp.toUTCString()
}

export function getQueryString (name: string): string | null {
  let search = location.search.substring(1)
  let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
  let r = search.match(reg)
  if (r != null) return decodeURIComponent(r[2])
  return null
}

export function between (val: number, min: number, max: number): number {
  return Math.max(Math.min(val, max), min)
}
/**
 * 格式化时间
 * @export
 * @param {Date} date 日期对象
 * @param {string} fmt 日期格式 例如 YYYY-mm-dd HH:MM:SS
 * @returns
 */
export function formatTime (date: Date, fmt: string = 'YYYY-mm-dd HH:MM:SS'): string {
  let ret
  const opt: any = {
    'Y+': date.getFullYear().toString(), // 年
    'm+': (date.getMonth() + 1).toString(), // 月
    'd+': date.getDate().toString(), // 日
    'H+': date.getHours().toString(), // 时
    'M+': date.getMinutes().toString(), // 分
    'S+': date.getSeconds().toString(), // 秒
    // 有其他格式化字符需求可以继续添加，必须转化成字符串
  }
  for (let k in opt) {
    ret = new RegExp('(' + k + ')').exec(fmt)
    if (ret) {
      fmt = fmt.replace(
        ret[1],
        ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0')
      )
    }
  }
  return fmt
}

/* eslint-disable */
function getLenthAfterPoint (v: number): number {
  let _v
  try {
    _v = v.toString().split('.')[1].length
  } catch (f) {
    _v = 0
  }
  return _v
}

export function add (a: number, b: number): number {
  const c = getLenthAfterPoint(a)
  const d = getLenthAfterPoint(b)
  const e = Math.pow(10, Math.max(c, d))
  return (mul(a, e) + mul(b, e)) / e
}

export function sub (a: number, b: number): number {
  const c = getLenthAfterPoint(a)
  const d = getLenthAfterPoint(b)
  const e = Math.pow(10, Math.max(c, d))
  return (mul(a, e) - mul(b, e)) / e
}

export function mul (a: number, b: number): number {
  let c = 0
  const d = a.toString()
  const e = b.toString()
  c += getLenthAfterPoint(a)
  c += getLenthAfterPoint(b)
  return (
    (Number(d.replace('.', '')) * Number(e.replace('.', ''))) / Math.pow(10, c)
  )
}

export function div (a: number, b: number): number {
  const e = getLenthAfterPoint(a)
  const f = getLenthAfterPoint(b)
  const c = a.toString().replace('.', '')
  const d = b.toString().replace('.', '')
  if (c.length > 10 || d.length > 10) {
    const max = Math.pow(10, 14)
    return Math.round((a / b) * max) / max
  }
  return mul(Number(c) / Number(d), Math.pow(10, f - e))
}

export function mol (a: number, b: number): number {
  const c = getLenthAfterPoint(a)
  const d = getLenthAfterPoint(b)
  const e = Math.pow(10, Math.max(c, d))
  return (mul(a, e) % mul(b, e)) / e
}

export function throttle (
  delay: number,
  action: Function,
  immediately: boolean
): Function {
  let last = 0
  let id = -1
  return function (this: any, ...args: any[]) {
    if (last === 0 && immediately) {
      action.apply(this, args)
      last = +new Date()
      return
    }
    clearTimeout(id)
    const curr = +new Date()
    if (curr - last > delay) {
      action.apply(this, args)
      last = curr
    } else {
      id = window.setTimeout(() => action.apply(this, args), delay)
      return id
    }
  }
}

export function debounce (
  delay: number,
  action: Function,
  immediately = false,
  alwaysImmediately = false
) {
  let id = -1
  return function (this: any, ...args: any[]) {
    if (immediately && id === -1) {
      action.apply(this, args)
    }
    clearTimeout(id)
    id = window.setTimeout(() => {
      action.apply(this, args)
      if (alwaysImmediately) {
        id = -1
      }
    }, delay)
    return id
  }
}


export function formatSize (byte: number) {
  if (byte === 0) return '0 B'
  let k = 1024
  let sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  let i = Math.floor(Math.log(byte) / Math.log(k))
  return toFixed((byte / Math.pow(k, i)), 2) + ' ' + sizes[i]
}

export function getNowDateTime () {
  return formatTime(new Date(), 'YYYY-mm-dd HH:MM:SS')
}

export function clone<T extends Object> (source: T) {
  return JSON.parse(JSON.stringify(source)) as T
}

export function getValue (...argvs: any[]): any {
  for (let i of argvs) {
    if (i !== undefined && i !== null && !Number.isNaN(i)) {
      return i
    }
  }
  return argvs[argvs.length - 1]
}

export function catchedPromise<T> (promise: Promise<T>) {
  return promise.catch((err) => {
    console.warn(err)
    return Promise.resolve()
  })
}

const map = new Map<string, (this: any, ...args: any[]) => number>()
export function debounceBy (keyed: string | (() => string), action: Function) {
  const key = typeof keyed === 'function' ? keyed() : keyed
  if (map.get(key)) {
    return map.get(key)!()
  } else {
    const func = debounce(500, action)
    map.set(key, func)
    func()
  }
}

export function delay (timeout: number, action: Function) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(action())
    }, timeout)
  })
}

export function toFixed (num: number, digits: number) {
  return div(Math.round(mul(num, Math.pow(10, digits))), Math.pow(10, digits))
}

export function getDay (start: string, end: string) {
  let dateSpan, iDays
  dateSpan = +new Date(end) - (+new Date(start))
  iDays = Math.floor(dateSpan / (24 * 3600 * 1000))
  return iDays;
}